#include <iostream>
#include <sys/types.h>
#include <cerrno>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

void service(int new_sock)
{
    while (1)
    {
        char buffer[1024];
        memset(buffer, 0, sizeof(buffer));
        size_t s = read(new_sock, buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << "#client 发送: " << buffer << std::endl;

            // 读到客户端发送的数据之后，向客户端发送返回的数据
            std::string msg = "sever echo: ";
            msg += buffer;
            write(new_sock, msg.c_str(), msg.size());
        }
        else if (s == 0)
        {
            std::cout << "client quit" << std::endl;
            break;
        }
        else
        {
            std::cout << "read error" << std::endl;
            break;
        }
    }
}

int main(int args, char *argv[])
{

    signal(SIGCHLD, SIG_IGN);
    // 1.创建套接字
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0)
    {
        std::cout << "listen_socket create erro" << errno << std::endl;
        return 1;
    }

    // 2.绑定IP+端口号
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = INADDR_ANY;
    local.sin_port = htons(atoi(argv[1]));
    if (bind(listen_sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        std::cout << "bind error" << std::endl;
        return 2;
    }

    // 3.TCP是面向连接的，所以得先监听
    const int back_log = 5;
    if (listen(listen_sock, back_log) < 0)
    {
        std::cout << "listen error" << std::endl;
        return 3;
    }

    // 4.监听到连接之后，在进行获取连接，获取连接如果没有获取成功，需要不断进行获取，所以需要循环
    for (;;)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int new_sock = accept(listen_sock, (struct sockaddr *)&peer, &len);
        if (new_sock < 0)
        {
            continue;
        }

        // 5.获取连接成功,提供服务

        std::cout << "获取连接成功：" << new_sock << std::endl;
    

    // 创建子进程，让子进程去创建服务
    pid_t id = fork();
    if (id == 0)
    {
        // 子进程，子进程继承父进程的文件描述符，但是是两份文件描述符，都指向了打开的同一文件
        // 1.关闭父进程继承下来的监听套接字
        close(listen_sock);
        // 2.提供服务
        service(new_sock);
        // 3.服务提供结束之后，子进程关闭连接之后的新套接字
        close(new_sock);
        exit(0);
    }
    else if (id > 0)
    {
        // 父进程
        // 要不要等待子进程？
        // 如果是阻塞式等待，就必须等待子进程运行结束之后，父进程才能继续往下运行
        // 这样的话还是相当于是串行的连接，所以我们不予等待，再开始忽略子进程的sigchild即可
        // 父进程忽略子进程的sigchild信号之后，操作系统会自动回收子进程的相关资源，子进程同样
        // 不会成为僵尸进程
        //所以父进程啥都不用做
    }
    else
    {
        continue;
    }
}
    return 0;
}